import mimetypes
from typing import List, Optional

from fastapi import APIRouter, File, UploadFile, HTTPException, Response, Form, Depends
from loguru import logger
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from ai_platform.config.resource import get_minio_service, get_kafka_service, get_db_engine
from ai_platform.config.settings import settings
from ai_platform.models import UploadedFile
from ai_platform.models.user import User
from ai_platform.services.knowledge_service import knowledge_service
from .common import ApiResponse, success_response, error_response
from .dependencies import require_auth, require_admin
from ..pipeline.data_pipeline import FileDataPipeline
from ..services.kafka_service import MessageModel

router = APIRouter(prefix="/api/files", tags=["文件管理"])

# 常量定义
MAX_FILE_SIZE = 100 * 1024 * 1024  # 100MB
MAX_BATCH_UPLOAD_COUNT = 10
SUPPORTED_TEXT_EXTENSIONS = {
    'txt', 'md', 'markdown', 'json', 'xml', 'csv',
    'log', 'py', 'js', 'html', 'css', 'yml', 'yaml'
}


# 简化的模型定义
class FileUploadResult(BaseModel):
    """文件上传结果模型"""
    filename: str = Field(description="文件名", examples=["document.pdf"])
    file_id: str = Field(description="文件ID", examples=["file_123"])
    file_size: int = Field(description="文件大小（字节）", examples=[1024000])
    file_type: str = Field(description="文件类型", examples=["pdf"])
    object_name: str = Field(description="存储对象名", examples=["2024/01/document.pdf"])
    knowledge_base_added: bool = Field(default=False, description="是否已添加到知识库", examples=[True])
    kb_file_id: Optional[str] = Field(default=None, description="知识库文件ID", examples=["kbf_123"])


class KnowledgeBaseInfo(BaseModel):
    """知识库信息模型"""
    id: str = Field(description="知识库ID", examples=["kb_123"])
    name: str = Field(description="知识库名称", examples=["技术文档库"])
    description: Optional[str] = Field(default=None, description="知识库描述", examples=["存储技术相关文档"])
    status: str = Field(description="知识库状态", examples=["active"])
    created_at: str = Field(description="创建时间", examples=["2024-01-01T00:00:00"])


class FileInfo(BaseModel):
    """文件信息模型"""
    name: str = Field(description="文件名", examples=["document.pdf"])
    size: int = Field(description="文件大小", examples=[1024000])
    last_modified: str = Field(description="最后修改时间", examples=["2024-01-01T12:00:00"])
    etag: str = Field(description="文件ETag", examples=["abc123"])
    content_type: Optional[str] = Field(default=None, description="文件MIME类型", examples=["application/pdf"])


class FileListResponse(BaseModel):
    """文件列表响应模型"""
    success: bool = Field(description="请求是否成功", examples=[True])
    files: List[dict] = Field(description="文件列表")
    total: int = Field(description="文件总数", examples=[10])


# 辅助函数
def get_file_type(filename: str) -> str:
    """获取文件类型"""
    return filename.split('.')[-1].lower() if '.' in filename else 'unknown'


def validate_file_size(file_data: bytes) -> None:
    """验证文件大小"""
    if len(file_data) == 0:
        raise HTTPException(status_code=400, detail="文件内容不能为空")
    if len(file_data) > MAX_FILE_SIZE:
        raise HTTPException(status_code=413, detail="文件大小不能超过100MB")


# 路由定义
@router.post("/upload",
             response_model=ApiResponse[FileUploadResult],
             summary="上传文件",
             description="""
    ## 文件上传接口
    
    上传单个文件到系统，支持多种文件格式。
    
    ### 功能特点
    - 支持多种文件格式（PDF、TXT、MD、DOCX等）
    - 文件大小限制：100MB
    - 可选择添加到指定知识库
    - 自动文件类型检测和验证
    - 异步处理，支持大文件上传
    
    ### 支持的文件格式
    - **文档**: PDF, DOC, DOCX, TXT, MD
    - **数据**: CSV, JSON, XML, YAML
    - **代码**: PY, JS, HTML, CSS
    - **其他**: LOG等文本文件
    
    ### 请求参数
    - **file**: 要上传的文件（必需）
    - **knowledge_base_id**: 知识库ID（可选，将文件添加到指定知识库）
    
    ### 处理流程
    1. 验证文件大小和格式
    2. 上传文件到存储系统
    3. 创建文件记录
    4. 可选：添加到知识库
    5. 发送处理消息到队列
    
    ### 错误码
    - **400**: 文件验证失败（空文件、格式不支持等）
    - **404**: 指定的知识库不存在
    - **413**: 文件大小超过限制
    - **500**: 服务器内部错误
    """,
             responses={
                 200: {
                     "description": "文件上传成功",
                     "content": {
                         "application/json": {
                             "example": {
                                 "success": True,
                                 "message": "文件上传成功并已添加到知识库",
                                 "data": {
                                     "filename": "document.pdf",
                                     "file_id": "file_123",
                                     "file_size": 1024000,
                                     "file_type": "pdf",
                                     "object_name": "2024/01/document.pdf",
                                     "knowledge_base_added": True,
                                     "kb_file_id": "kbf_123"
                                 }
                             }
                         }
                     }
                 },
                 400: {
                     "description": "文件验证失败",
                     "content": {
                         "application/json": {
                             "example": {"detail": "文件内容不能为空"}
                         }
                     }
                 },
                 413: {
                     "description": "文件太大",
                     "content": {
                         "application/json": {
                             "example": {"detail": "文件大小不能超过100MB"}
                         }
                     }
                 }
             }
             )
async def upload_file(
    file: UploadFile = File(..., description="要上传的文件"),
    knowledge_base_id: Optional[str] = Form(None, description="可选的知识库ID"),
    _: User = Depends(require_auth)
):
    """上传单个文件并可选择添加到知识库"""
    try:
        if not file.filename:
            raise HTTPException(status_code=400, detail="文件名不能为空")

        # 读取和验证文件
        file_data = await file.read()
        validate_file_size(file_data)

        # 验证知识库
        if knowledge_base_id:
            kb = await knowledge_service.get_knowledge_base(knowledge_base_id)
            if not kb:
                raise HTTPException(status_code=404, detail="指定的知识库不存在")

        # 上传文件
        minio_service = get_minio_service()
        # kafka_service = get_kafka_service()

        upload_info = await minio_service.upload_file(
            knowledge_base_id,
            settings.minio_bucket,
            file_data=file_data,
            original_filename=file.filename,
            content_type=file.content_type or "application/octet-stream"
        )

        # 创建文件记录
        uploaded_file = await knowledge_service.create_uploaded_file(
            filename=upload_info.get("filename", file.filename),
            original_filename=file.filename,
            file_path=upload_info.get("object_name", ""),
            file_size=len(file_data),
            file_type=get_file_type(file.filename),
            mime_type=file.content_type
        )

        # 构建响应数据
        result = FileUploadResult(
            filename=uploaded_file.filename,
            file_id=uploaded_file.id,
            file_size=uploaded_file.file_size,
            file_type=uploaded_file.file_type,
            object_name=upload_info.get("object_name", "")
        )

        # 添加到知识库
        success_message = "文件上传成功"
        if knowledge_base_id:
            try:
                added_files, _ = await knowledge_service.add_files_to_knowledge_base(
                    knowledge_base_id, [uploaded_file.id]
                )
                if added_files:
                    result.knowledge_base_added = True
                    result.kb_file_id = added_files[0].id
                    success_message += "并已添加到知识库"
            except Exception as e:
                logger.warning(f"文件上传成功但添加到知识库失败: {e}")

        # 发送Kafka消息
        # await kafka_service.send_file_upload_message(upload_info)
        # 临时使用
        message = MessageModel(
            event_type="file_upload",
            file_id=upload_info["file_id"],
            original_filename=upload_info["original_filename"],
            download_url=upload_info["download_url"],
            file_size=upload_info["file_size"],
            content_type=upload_info["content_type"],
            upload_time=upload_info["upload_time"],
            bucket_name=upload_info["bucket_name"],
            object_name=upload_info["object_name"],
            knowledge_base_id=upload_info["knowledge_base_id"]
        )

        pipeline = FileDataPipeline()
        await pipeline.process_minio_file(knowledge_base_id=message.knowledge_base_id,
                                          object_name=message.object_name,
                                          bucket_name=message.bucket_name)

        return ApiResponse(
            success=True,
            message=success_message,
            data=result
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"文件上传失败: {e}")
        raise HTTPException(status_code=500, detail=f"文件上传失败: {str(e)}")


@router.get("/knowledge-bases",
            summary="获取知识库列表",
            description="""
    ## 获取可用知识库列表
    
    获取当前用户可以使用的知识库列表，用于文件上传时选择目标知识库。
    
    ### 功能特点
    - 只返回状态为活跃的知识库
    - 包含知识库基本信息
    - 支持大量知识库的查询
    
    ### 返回信息
    - 知识库ID和名称
    - 知识库描述和状态
    - 创建时间
    
    ### 错误码
    - **401**: 未认证或会话已过期
    - **500**: 服务器内部错误
    """,
            responses={
                200: {
                    "description": "获取知识库列表成功",
                    "content": {
                        "application/json": {
                            "example": {
                                "success": True,
                                "message": "获取成功",
                                "data": {
                                    "knowledge_bases": [
                                        {
                                            "id": "kb_123",
                                            "name": "技术文档库",
                                            "description": "存储技术相关文档",
                                            "status": "active",
                                            "created_at": "2024-01-01T00:00:00"
                                        }
                                    ],
                                    "total": 1
                                }
                            }
                        }
                    }
                }
            }
            )
async def get_knowledge_bases_for_upload(_: User = Depends(require_auth)):
    """获取可选择的知识库列表"""
    try:
        kbs, total = await knowledge_service.list_knowledge_bases(limit=100, status="active")

        kb_list = [
            KnowledgeBaseInfo(
                id=kb.id,
                name=kb.name,
                description=kb.description,
                status=kb.status,
                created_at=kb.created_at.isoformat()
            )
            for kb in kbs
        ]

        return success_response(data={"knowledge_bases": kb_list, "total": total})

    except Exception as e:
        logger.exception(f"获取知识库列表失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取知识库列表失败: {str(e)}")


@router.get("/list",
            response_model=FileListResponse,
            summary="获取文件列表",
            description="""
    ## 获取文件列表接口
    
    获取存储系统中的文件列表，支持按前缀过滤和分页。
    
    ### 功能特点
    - 分页获取文件列表
    - 支持前缀过滤（按路径或名称）
    - 显示文件详细信息
    
    ### 查询参数
    - **prefix**: 文件名前缀过滤（可选）
    - **limit**: 返回数量限制（默认50）
    
    ### 返回信息
    - 文件名和大小
    - 最后修改时间
    - 文件ETag和MIME类型
    
    ### 使用场景
    - 文件管理界面
    - 文件浏览和搜索
    - 批量操作选择
    
    ### 错误码
    - **401**: 未认证或会话已过期
    - **500**: 服务器内部错误
    """,
            responses={
                200: {
                    "description": "获取文件列表成功",
                    "content": {
                        "application/json": {
                            "example": {
                                "success": True,
                                "files": [
                                    {
                                        "name": "document.pdf",
                                        "size": 1024000,
                                        "last_modified": "2024-01-01T12:00:00",
                                        "etag": "abc123",
                                        "content_type": "application/pdf"
                                    }
                                ],
                                "total": 1
                            }
                        }
                    }
                }
            }
            )
async def list_files(
    prefix: str = "",
    limit: int = 50,
    _: User = Depends(require_auth)
):
    """获取文件列表"""
    try:
        minio_service = get_minio_service()
        files = await minio_service.list_files(settings.minio_bucket, prefix=prefix, limit=limit)

        return FileListResponse(
            success=True,
            files=files,
            total=len(files)
        )

    except Exception as e:
        logger.exception(f"获取文件列表失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取文件列表失败: {str(e)}")


@router.delete("/delete/{object_name:path}")
async def delete_file(object_name: str, _: User = Depends(require_admin)):
    """删除文件"""
    try:
        minio_service = get_minio_service()

        # 先根据object_name查找数据库中的文件记录
        file_record = None
        try:
            # 通过object_name(file_path)查找文件记录
            engine = get_db_engine()
            async with AsyncSession(engine) as session:
                stmt = select(UploadedFile).where(UploadedFile.file_path == object_name)
                result = await session.execute(stmt)
                file_record = result.scalars().first()
        except Exception as e:
            logger.warning(f"查找文件记录时出错: {e}")

        # 删除MinIO中的文件
        minio_success = await minio_service.delete_file(settings.minio_bucket, object_name)

        # 删除数据库中的文件记录
        db_success = False
        if file_record:
            try:
                db_success = await knowledge_service.delete_uploaded_file(file_record.id)
                if db_success:
                    logger.info(f"删除数据库文件记录成功: {file_record.id}")
                else:
                    logger.warning(f"删除数据库文件记录失败: {file_record.id}")
            except Exception as e:
                logger.exception(f"删除数据库文件记录时出错: {e}")
        else:
            logger.warning(f"未找到object_name为 {object_name} 的文件记录")
            db_success = True  # 如果数据库中没有记录，认为删除成功

        if minio_success and db_success:
            message = "文件删除成功"
            if file_record:
                message += f"，同时删除了数据库记录"
            return success_response(message=message)
        elif minio_success and not db_success:
            return success_response(message="文件删除成功，但数据库记录删除失败")
        elif not minio_success and db_success:
            return error_response(message="MinIO文件删除失败，但数据库记录已删除")
        else:
            return error_response(message="文件删除失败")

    except Exception as e:
        logger.exception(f"删除文件失败: {e}")
        raise HTTPException(status_code=500, detail=f"删除文件失败: {str(e)}")


@router.get("/info/{object_name:path}")
async def get_file_info(object_name: str, _: User = Depends(require_auth)):
    """获取文件信息"""
    try:
        minio_service = get_minio_service()
        file_info = await minio_service.get_file_info(settings.minio_bucket, object_name)

        if file_info:
            info = FileInfo(
                name=file_info.get("name", object_name),
                size=file_info.get("size", 0),
                last_modified=file_info.get("last_modified", ""),
                etag=file_info.get("etag", ""),
                content_type=file_info.get("content_type")
            )
            return success_response(data=info.model_dump(), message="获取文件信息成功")
        else:
            raise HTTPException(status_code=404, detail="文件不存在")

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"获取文件信息失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取文件信息失败: {str(e)}")


@router.get("/download/{object_name:path}")
async def get_download_url(object_name: str, expires: int = 3600, _: User = Depends(require_auth)):
    """获取文件下载URL"""
    try:
        minio_service = get_minio_service()
        download_url = minio_service.get_download_url(settings.minio_bucket, object_name, expires)

        return success_response(
            data={
                "download_url": download_url,
                "expires_in": expires
            },
            message="获取下载链接成功"
        )

    except Exception as e:
        logger.exception(f"获取下载URL失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取下载URL失败: {str(e)}")


@router.get("/preview/{object_name:path}")
async def get_file_preview(object_name: str, _: User = Depends(require_auth)):
    """获取文件预览（用于图片、PDF等直接预览）"""
    try:
        minio_service = get_minio_service()
        file_data = await minio_service.read_file(settings.minio_bucket, object_name)

        if not file_data:
            raise HTTPException(status_code=404, detail="文件不存在")

        # 根据文件扩展名确定MIME类型
        mime_type, _ = mimetypes.guess_type(object_name)
        if not mime_type:
            mime_type = "application/octet-stream"

        return Response(
            content=file_data,
            media_type=mime_type,
            headers={
                "Content-Disposition": f"inline; filename={object_name.split('/')[-1]}",
                "Cache-Control": "public, max-age=3600"
            }
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"获取文件预览失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取文件预览失败: {str(e)}")


@router.get("/content/{object_name:path}")
async def get_file_content(object_name: str, _: User = Depends(require_auth)):
    """获取文件内容（用于文本文件预览）"""
    try:
        # 检查文件扩展名
        file_extension = object_name.split('.')[-1].lower() if '.' in object_name else ''
        if file_extension not in SUPPORTED_TEXT_EXTENSIONS:
            raise HTTPException(status_code=400, detail=f"不支持的文件类型: {file_extension}")

        minio_service = get_minio_service()
        file_data = await minio_service.read_file(settings.minio_bucket, object_name)

        if not file_data:
            raise HTTPException(status_code=404, detail="文件不存在")

        # 尝试解码文件内容
        try:
            content = file_data.decode('utf-8')
        except UnicodeDecodeError:
            try:
                content = file_data.decode('gbk')
            except UnicodeDecodeError:
                try:
                    content = file_data.decode('latin-1')
                except UnicodeDecodeError:
                    raise HTTPException(status_code=400, detail="无法解码文件内容")

        # 限制返回大小
        if len(content) > 1024 * 1024:  # 1MB
            content = content[:1024 * 1024] + "\n\n... (文件过大，已截断显示)"

        return Response(
            content=content,
            media_type="text/plain; charset=utf-8",
            headers={"Content-Disposition": f"inline; filename={object_name}"}
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"获取文件内容失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取文件内容失败: {str(e)}")
